# Tiny HTTP server docker image based on BusyBox and C

Create a new directory to keep everything organized. I have used port `8081` to keep things different from inside container and out. But you can use any port you wish.

This should create a simple HTTP server for static files. The image should be around ~2mb in size. BusyBox (musl) should take ~1.47mb (smaller than Alpine Linux) and tiny-web-server written in C when built for musl will be around ~75kb. Compare that to a latest nginx image being 126MB when I'm writing this. This would be an overkill for a static server, hence this C based one.


## Building the `tiny-web-server`

[tiny-web-server](https://github.com/shenfeng/tiny-web-server) is just excellent for a simple, tiny, static file web server. It is written in C, so it's efficient and the executable is very small (~30kb) and ideal for a small docker image. It is just one file of C code but still does the job wonderfully.

There are no binary releases on the GitHub project, so we'll have to build it ourselves. But not to worry, it's so easy and so short nearly anybody can do it.

From the folder we created for our project, let's clone the repo:
```
git clone --depth=1 https://github.com/shenfeng/tiny-web-server.git
cd tiny-web-server
```

Now let's build it. You will need to have `gcc` plus musl cross compile packages installed, then run:

I was on Void Linux x86_64, so I ran:
```
sudo xbps-install cross-x86_64-linux-musl
```

Then, to build the binary:
```
x86_64-linux-musl-gcc -static -o server tiny.c
```

As sidenote, if I were to run it on my computer outside of docker image I would do `gcc -o server tiny.c`. But we're not doing that. BTW, if you run normal executables in the busybox docker, you'll see a [`standard_init_linux.go:211: exec user process caused "no such file or directory"` error](https://stackoverflow.com/questions/56832363/docker-standard-init-linux-go211-exec-user-process-caused-no-such-file-or-di). That's why we're building this way. `-o` is for output. `-static` is to link the required libraries statically inside the executable. This is to keep it simple and to cause minimal trouble running this inside docker. So this command will output a binary file named `server`. It will take merely seconds (if not less) to build it and it's so tiny and basic, practically no errors should show up. So easy!

Now let's put that on our main folder and tidy up things:

```
cd ..
cp tiny-web-server/server ./
# optional: delete the repo folder
rm -rf tiny-web-server
```

Check the file size. I built it on a Linux x86_64 machine and it was just ~75kb!! Amazing!

But there is [one issue](https://github.com/shenfeng/tiny-web-server/issues/7) with this server -- it does not go to index.html automatically if you go to a directory that has one. Maybe it's a flaw, maybe it's intentional, maybe you can edit the source code to do it exactly that. But I was busy so I didn't try. Just something to let you know.


## With Docker Compose

To me, with Docker Compose, it becomes a lot more cleaner and manageable. If you want to do this with Dockerfile, see below.

`nano docker-compose.yml`
```
web:
  image: busybox:musl
  volumes:
   - ./server:/bin/server
   - ./www:/www
  ports:
   - "8080:8081"
  command: /bin/server /www 8081
```

You can easily replace `image: busybox:musl` with `image: alpine` and it should still work (because Alpine is musl based). But Alpine is slightly larger than busybox. We're using `busybox:musl` variant because the default one is based on uClibc and building with it is very complicated (requires learning [Buildroot](https://buildroot.org/)).

You can run tiny-web-server 3 ways:
```
./server  # this will run the server on 9999 and consider the current directory as webroot
./server www # this will run the server on 9999 and consider the "www" directory as webroot
./server www 8089 # this will run the server on 8089 and consider the "www" directory as webroot
```

By default tiny-web-server runs on port 9999. So we are specifying `8081` as our port of choice and pointing to `www` for using our webroot.

Ensure that there is a `www` directory: `mkdir www`

Put an `index.html` file as a test: `echo "Your server is working!!" > www/index.html`


Now run: `docker-compose up` \
Open `http://localhost:8080` \
Ctrl+C to stop server


## With Dockerfile

You can also try this with Dockerfile.

`nano Dockerfile`
```
FROM busybox:musl
COPY ./server /bin/
COPY ./www /www
CMD /bin/server /www 8081
```

Build the image with:
```
docker build -t tinyc-server .
```

Verify it's created:
```
docker images | grep "tinyc-server"
```

Run it:
```
docker run -p 8080:8081 --rm -it tinyc-server
```

Now access your server from: `http://localhost:8080`
